// 引入头文件
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
// #include <winsock.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
# include<signal.h>
// 定义宏
#define MAXLINE 1024 // 缓冲区大小
#define TRUE 1
#define END "END\n" // 结束标志
#define USER "JERRY"   // 定义Client用户名

int main(int argc, char **argv)
{
    int sockfd, n, m; // 这里的sockfd是网络连接的套接字文件描述符，用于标记套接字接口
    char rec_line[MAXLINE + 1] , sen_line[MAXLINE + 1]; // 定义用于接受和发送数据的缓冲区
    struct sockaddr_in6 servaddr; // 定义服务器地址
    time_t t0 = time(NULL); // 定义时间变量，表示从Unix时间戳开始的时间
    fputs(ctime(&t0), stdout); // 使用ctime函数格式化打印出当前的本地时间
    printf("your user name is %s \n",USER);

    // 判断是否按照使用要求输入了服务器的地址
    if (argc != 2)
        perror("usage: a.out <IPaddress>"); // perror用于输出系统错误

    // 创建套接字，并判断是否创建失败
    if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
        // 当套接字文件描述符为负数的时候，创建失败
        perror("socket error");

    bzero(&servaddr, sizeof(servaddr)); // 将服务器地址所在的内存均写为0
    servaddr.sin6_family = AF_INET6; // 设置套接字地址类型为AF_INET6，即只接受IPv6地址
    servaddr.sin6_port = htons(20000); // 设置服务器端口为20000，其中htons把电脑上数据存储顺序的无符号短整型数转换成网络上的数据存储顺序的短整型数

    // 将数值地址转换成二进制形式，并存入servaddr.sin6_addr中，并判断是否转换成功
    if (inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr) <= 0)
        perror("inet_pton error");

    // 与服务器进行TCP连接，并判断是否连接成功
    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
        perror("connect error");

    char user[100]={};
    char send_message[MAXLINE+100]={};
    strcpy(user,USER);
    strcat(user,": ");

    // 创建子进程
    pid_t pid;
    pid = fork(); // 得到进程标识符
    if(pid <0)
        perror("fork error");

    if(pid==0){ //子进程中用来接受Server端数据
        while (TRUE)
        {
            bzero(rec_line,sizeof(rec_line)); //清空接受缓冲区
            n = read(sockfd,rec_line,sizeof(rec_line)); //接受server端发送的数据存到接收缓冲区，n为读取到的数据的长度
            if (n==-1)
                perror("read error");
            else if (n == 0){
                printf("server is close!\n");
                break; //子进程收到server端退出的信息,（server端Ctrl+C结束通信进程，read函数返回值为0，退出循环）
            }
            if(strcmp(rec_line,END)==0){ // 如果server端发送'END'结束信息，中断通信
                printf("receive signal to close chat.See you!\n");
                break;
            }
            rec_line[n] = 0; // 将读取到的数据的下一位写0，便于输出
            if (fputs(rec_line, stdout) == EOF)
                // 输出失败，引起错误
                perror("fputs error");
        }
        close(sockfd);// 子进程退出，通信结束关闭socket
        kill(getppid(),SIGUSR1);// 子进程结束，向父进程发出一个信号告诉父进程终止接收
        exit(EXIT_SUCCESS);// 子进程正常退出结束，向父进程返回EXIT_SUCCESS
    }
    else{
        while(fgets(sen_line,MAXLINE, stdin) != NULL){
            if (strcmp(sen_line,END)!=0){
                strcat(send_message,user);  // 在发送数据的前端加上用户名
                strcat(send_message,sen_line);
                n = write(sockfd, send_message, strlen(send_message)); //将发送缓冲区的数据发送给server端
            }
            else{
                n = write(sockfd, sen_line, strlen(sen_line)); //将发送缓冲区的数据发送给server端
            }
            if(n < 0)
                perror("write error");
            bzero(sen_line,strlen(sen_line)); //清空发送缓冲区
            bzero(send_message,strlen(send_message)); //清空发送信息  
        }
        close(sockfd);//通信结束，关闭socket
    }
    exit(0);
}